package com.sunnybear.framework.ui;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import java.util.concurrent.TimeUnit;

import androidx.recyclerview.widget.RecyclerView;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;

/**
 * <p>
 *  2018/7/27.
 */
public class LoadMoreAndRefreshLayout extends PullToRefreshLayout {

    private final byte[] lock = new byte[0];

    public LoadMoreAndRefreshLayout(Context context) {
        super(context);
    }

    public LoadMoreAndRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LoadMoreAndRefreshLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private View footer;

    public View getFooter() {
        return footer;
    }

    public void addFooter(View footer, LoadMoreListener loadMoreListener) {
        isRemoveFooter = false;
        if (mContent instanceof RecyclerView) {
            RecyclerView recyclerView = (RecyclerView) mContent;
            recyclerView.clearOnScrollListeners();
            recyclerView.addOnScrollListener(new RecyclerViewOnScrollListener());
        }
        ViewGroup.LayoutParams lp = footer.getLayoutParams();
        if (lp == null) {
            lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            footer.setLayoutParams(lp);
        }
        if (getChildCount() < 3) {
            this.footer = footer;
            setAddFooter(false);
        }
        mLoadMoreListener = loadMoreListener;
    }

    public void removeFooter() {
        isRemoveFooter = true;
    }

    @Override
    public void setOnRefreshListener(final OnRefreshListener onRefreshListener) {
        OnRefreshListener listener = new OnRefreshListener() {
            @Override
            public void onRefresh() {
                onRefreshListener.onRefresh();
                if (footer != null) {
                    removeView(footer);
                    footer = null;
                }
            }
        };
        super.setOnRefreshListener(listener);
    }

    class RecyclerViewOnScrollListener extends RecyclerView.OnScrollListener {

        public RecyclerViewOnScrollListener() {
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int
                newState) {
            if (change > 0) {
                atBottom = false;
            }
            if ((newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView
                    .SCROLL_STATE_DRAGGING) && isScrollBottom(recyclerView)) {
                atBottom = true;
                synchronized (lock) {
                    if (footer != null && !isAddFooter) {
                        setAddFooter(true);
                        addView(footer);
                    }
                }
            } else {
                initHeight = mContent.getMeasuredHeight();
                atBottom = false;
            }
        }

        private boolean isScrollBottom(RecyclerView recyclerView) {
            return !isCanScrollVertically(recyclerView);
        }

        private boolean isCanScrollVertically(RecyclerView recyclerView) {
            int count = recyclerView.getAdapter().getItemCount();
            if (count > 0) {
                int computeVerticalScrollRange = recyclerView.computeVerticalScrollRange() / count
                        * (count - 1);
                int computeVerticalScrollOffset = recyclerView.computeVerticalScrollOffset();
                int computeVerticalScrollExtent = recyclerView.computeVerticalScrollExtent();
                return computeVerticalScrollRange > computeVerticalScrollOffset +
                        computeVerticalScrollExtent;
            }
            return recyclerView.canScrollVertically(1);
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int
                dy) {
        }
    }

    /**
     * RecyclerView的初始高度
     */
    private float initHeight;
    /**
     * 触屏事件的位移
     */
    private float change;

    /**
     * 缓存的上次位置
     */
    private float lastY;

    /**
     * RecyclerView是否处于底部
     */
    private boolean atBottom;

    /**
     * 手指按下时RecyclerView是否处于底部
     */
    private boolean startBottom;

    /**
     * 执行收起动画
     */
    private Disposable disposable;

    /**
     * 是否在收起
     */
    private boolean isCollapse;

    /**
     * 是否去加载更多
     */
    private boolean isLoadMore;

    /**
     * 是否有更多数据加载
     */
    private boolean isResultLoadMore;
    private LoadMoreListener mLoadMoreListener;

    /**
     * 是否将底部加到布局当中
     */
    protected boolean isAddFooter;

    protected boolean isRemoveFooter;

    public interface LoadMoreListener {
        void load();

        boolean complete(boolean isResultLoadMore);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (isCollapse) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastY = event.getY();
                startBottom = atBottom;
                break;
            case MotionEvent.ACTION_MOVE:
                float current = event.getY();
                change = current - lastY;
                lastY = current;
                if (mContent.getMeasuredHeight() >= initHeight && change > 0) {
                    startBottom = false;
                }
                if (startBottom && footer != null && mContent.getTop() <= 0) {
                    footer.post(new Runnable() {
                        @Override
                        public void run() {
                            mContent.getLayoutParams().height = (int) (mContent.getMeasuredHeight() + 0.5 * change);
                            if (change < 0) {
                                mContent.scrollBy(0, -(int) (1.5 * change));
                            } else if (mContent.getMeasuredHeight() >= initHeight) {
                                atBottom = false;
                            }
                            requestLayout();
                        }
                    });
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (startBottom && mContent.getMeasuredHeight() < initHeight && mContent.getTop() <= 0) {
                    if (mContent.getMeasuredHeight() < initHeight - footer.getMeasuredHeight()) {
                        collapseFooterToShow();
                    } else {

                        collapseFooterToHide();
                    }
                }
                break;
        }
        if (mContent.getMeasuredHeight() < initHeight) {
            return true;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    protected void onLayout(boolean flag, int leftLayout, int topLayout, int rightLayout, int bottomLayout) {
        super.onLayout(flag, leftLayout, topLayout, rightLayout, bottomLayout);
        initHeight = (float) bottomLayout - topLayout;
        if (footer != null) {
            int paddingLeft = getPaddingLeft();
            final int left = paddingLeft;
            float height = initHeight;
            if (initHeight <= 0 || height < bottomLayout) {
                height = bottomLayout;
            }
            final int top = (int) (height + (mContent.getMeasuredHeight() - height));
            final int right = left + footer.getMeasuredWidth();
            final int bottom = top + footer.getMeasuredHeight();
            footer.layout(left, top, right, bottom);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureFooterView(footer, widthMeasureSpec, heightMeasureSpec);
    }

    private void measureFooterView(View child,
                                   int parentWidthMeasureSpec,
                                   int parentHeightMeasureSpec) {
        if (child == null) {
            return;
        }
        final ViewGroup.LayoutParams lp = child.getLayoutParams();
        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                getPaddingLeft() + getPaddingRight(), lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                getPaddingTop() + getPaddingBottom(), lp.height);
        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

    /**
     * 延时后折叠footer收起
     */
    @SuppressLint("CheckResult")
    public void delayCollapseFooterToHide(boolean isResultLoadMore) {
        isCollapse = true;
        this.isResultLoadMore = isResultLoadMore;
        Flowable.timer(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        collapseFooterToHide();
                    }
                });
    }


    /**
     * 折叠footer收起
     */
    private void collapseFooterToHide() {
        isCollapse = true;
        disposable = Flowable.interval(33, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                .take(10)
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        if (LoadMoreAndRefreshLayout.this.isShown()) {
                            mContent.getLayoutParams().height += (int) ((initHeight - mContent.getMeasuredHeight()) / 3);
                            if (aLong >= 9) {
                                change = 0;
                                mContent.getLayoutParams().height = (int) initHeight;
                                isCollapse = false;
                                if (footer != null) {
                                    removeView(footer);
                                    setAddFooter(false);
                                    if (isRemoveFooter) {
                                        footer = null;
                                    }
                                }
                                if (isLoadMore) {
                                    boolean isLoad = mLoadMoreListener.complete(isResultLoadMore);
                                    atBottom = !isLoad;
                                    startBottom = !isLoad;
                                } else {
                                    atBottom = true;
                                    startBottom = true;
                                }
                                isLoadMore = false;
                            }
                            requestLayout();
                        }
                    }
                });
    }

    /**
     * 折叠footer到合适的位置
     */
    private void collapseFooterToShow() {
        isCollapse = true;
        mLoadMoreListener.load();
        isLoadMore = true;
        disposable = Flowable.interval(33, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                .take(16)
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        if (LoadMoreAndRefreshLayout.this.isShown()) {
                            int location = footer.getMeasuredHeight();
                            if (aLong < 15) {
                                mContent.getLayoutParams().height += (int) ((initHeight - location - mContent.getMeasuredHeight
                                        ()) / 3);
                            } else if (aLong == 15) {
                                change = 0;
                                mContent.getLayoutParams().height = (int) (initHeight - location);
                            }
                            requestLayout();
                        }
                    }
                });
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }

    private void setAddFooter(boolean addFooter) {
        synchronized (lock) {
            isAddFooter = addFooter;
        }
    }
}
